package com.share.example.stock.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.share.common.utils.ThreadUtil;
import com.share.common.utils.ObjUtil;
import com.share.common.utils.PinYinUtil;
import com.share.example.stock.enums.IndicatorEnum;
import com.share.example.stock.mapper.SectorDetailMapper;
import com.share.example.stock.mapper.SectorSpotMapper;
import com.share.example.stock.mapper.StockBaseInfoMapper;
import com.share.example.stock.model.ak.OpenCloseLowHigh;
import com.share.example.stock.model.db.SectorDetail;
import com.share.example.stock.model.db.SectorSpot;
import com.share.example.stock.model.db.StockBaseInfo;
import com.share.example.stock.service.AkService;
import com.share.example.stock.service.ISectorDetailService;
import com.share.example.stock.service.IStockBaseInfoService;
import com.share.example.stock.utils.CalcUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 目标地址: http://finance.sina.com.cn/sl/#area_1
 * 描述: 获取新浪行业-板块行情-成份详情
 * 限量: 单次获取指定的新浪行业-板块行情-成份详情  服务实现类
 * </p>
 *
 * @author author
 * @since 2023-06-03
 */

@Slf4j
@Service
public class SectorDetailServiceImpl extends ServiceImpl<SectorDetailMapper, SectorDetail> implements ISectorDetailService {
    //连续清理记错计数器
    private AtomicInteger errorCount = new AtomicInteger(0);

    @Resource
    private SectorDetailMapper sectorDetailMapper;
    @Resource
    private SectorSpotMapper sectorSpotMapper;
    @Resource
    private IStockBaseInfoService iStockBaseInfoService;
    @Resource
    private StockBaseInfoMapper stockBaseInfoMapper;
    @Autowired
    private AkService akHttpService;

    //重置错误id
    @Override
    public void resetErrorCount(int init) {
        errorCount.set(init);
    }

    @Override
    public Map<String, List<String>> downSectorDetail(List<SectorSpot> lables, String strTradeDate) {
        //key是code,标签名
        Map<String, List<String>> reMap = new HashMap<>();

        if (CollectionUtils.isEmpty(lables)) {
            return reMap;
        }

        for (SectorSpot spot : lables) {
            String lable = spot.getLable();
            int sleepTime = 100;
            try {
                List<SectorDetail> dataList = akHttpService.stock_sector_detail(lable, strTradeDate);
                log.info("拉取lable={},条数={}", lable, dataList.size());
                if (!CollectionUtils.isEmpty(dataList)) {
                    //1.数据分析
                    Date date = new Date();
                    List<String> list = new LinkedList<>();
                    for (SectorDetail item : dataList) {
                        //给item追加内容, 价格均值计算
                        OpenCloseLowHigh cp = CalcUtil.calcPrice(item.getOpen(), item.getTrade(), item.getLow(), item.getHigh());
                        item.setHlO(cp.getHighSlowDopen());
                        item.setCoO(cp.getCloseSopenDopen());
                        item.setHl(cp.getHighSlow());
                        item.setCo(cp.getCloseSopen());
                        item.setClHl(cp.getCloseSlowDhighSlow());
                        item.setOlHl(cp.getOpenSlowDhighSlow());
                        item.setHcHl(cp.getHighScloseDhighSlow());
                        item.setHoHl(cp.getHighSopenDhighSlow());
                        item.setAvgHl(cp.getAvghighSlow());
                        item.setAvgOc(cp.getAvgOpenclose());

                        String code = item.getCode();
                        String plate = item.getPlate();
                        if (StringUtils.isEmpty(plate)) {
                            continue;
                        }

                        //给iStockBaseInfoService标记板块信息
                        StockBaseInfo info = iStockBaseInfoService.getStockCodeMap(code);
                        StockBaseInfo record = new StockBaseInfo();
                        record.setCode(code);
                        record.setPlatesUpdateTime(date);

                        String indicator = spot.getIndicator();//新浪行业,gn,hy,地域
                        if (IndicatorEnum.HY.getCode().equals(indicator)) {
                            if (info != null && info.getHyPlates() != null && info.getHyPlates().contains(plate)) {
                                //数据库中存在,则跳过
                            } else {
                                record.setHyPlates(plate);
                            }
                        } else if (IndicatorEnum.GN.getCode().equals(indicator)) {
                            if (info != null && info.getGnPlates() != null && info.getGnPlates().contains(plate)) {
                                //数据库中存在,则跳过
                            } else {
                                record.setGnPlates(plate);
                            }
                        }

                        //数值校验
                        Map<String, Object> infoMap = ObjUtil.toMapIgnoreNull(record);
                        if (infoMap != null && infoMap.size() > 2) {
                            //顺带更新这2个字段,注意位置
                            record.setName(item.getName());
                            record.setNameFc(PinYinUtil.spellFirstCharSkipAlpha(item.getName()));
                            record.setCodePrefix3(item.getCode().substring(0,3));
                            ThreadUtil.execute(() -> stockBaseInfoMapper.appendPlatesByCode(record));//异步执行
                        } else {
                            log.info("数据异常item={}", JSON.toJSONString(item));
                        }
                        list.add(code);
                    }

                    //2.dataList排名数据处理
                    SectorSpot record = new SectorSpot();
                    Collections.sort(dataList, (a, b) -> {
                        return a.getChangepercent().compareTo(b.getChangepercent());
                    });
                    int size = dataList.size();
                    List<String> startList = null;
                    List<String> endList = null;
                    if (size <= 6) {
                        startList = dataList.stream().map(e -> e.getCode()).collect(Collectors.toList());
                        endList = startList;
                    } else {
                        startList = dataList.subList(0, 6).stream().map(e -> e.getCode()).collect(Collectors.toList());
                        endList = dataList.subList(size - 6, size - 1).stream().map(e -> e.getCode()).collect(Collectors.toList());
                    }
                    record.setTopCodes6pu(String.join(",", endList));
                    record.setTopCodes6pd(String.join(",", startList));
                    record.setDate(strTradeDate);
                    ThreadUtil.execute(() -> sectorSpotMapper.updateByLableAndDate(lable,record));

                    //3.数据入库-----慢就慢点吧
                    int countd = sectorDetailMapper.deleteByDateAndlable(strTradeDate, lable);  //删除不能异步

                    log.info("lable={},批量插入size={}", lable, dataList.size());
                    sectorDetailMapper.insertbatch(dataList);//

                    //返回数据处理
                    reMap.put(lable, list);

                    errorCount.set(0);//数值清0
                } else {
                    //请求无数据的时候 ---- 对应的逻辑
                    sleepTime = 3000;
                    errorCount.addAndGet(1);//失败就加1
                }
            } catch (Exception e) {
                sleepTime = 3000;
                errorCount.addAndGet(1);//失败就加1
            }

            //安全跳出----一直拉取数据会被警用ip
            if (errorCount.get() >= 3) {
                log.error("程序即将中断,连续调用多次异常,次数={}", errorCount.get());
                break;
            }

            //请求之后都调用延迟下
            try {
                Thread.sleep(sleepTime);//调用异常就延迟的长一点
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return reMap;
    }
}
